/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_kit/zhiqim_git.htm
 *
 * ZhiqimGit is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.git.util;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.zhiqim.git.Git;
import org.zhiqim.git.GitConstants;
import org.zhiqim.git.GitRefer;
import org.zhiqim.git.objer.objectid.ObjectId;
import org.zhiqim.git.refer.Ref;

import org.zhiqim.kernel.util.Bytes;
import org.zhiqim.kernel.util.Files;

/**
 * Git的验证工具类（统一管理）
 *
 * @version v1.0.0 @author zouzhigang 2017-3-31 新建与整理
 */
public class GitValidates implements GitConstants
{
    /** 判断是否是Git仓库 */
    public static boolean isGitRepository(File dir)
    {
        return Files.exists(dir, "objects") && Files.exists(dir, "refs") && isValidHead(new File(dir, HEAD));
    }
    
    /** 判断是不是有效的头文件 */
    public static boolean isValidHead(File head)
    {
        byte[] buf = Files.read(head, 4096);
        if (buf == null || buf.length == 0)
            return false;

        String ref = Bytes.BU.getString(buf, 0, _LF_);
        return ref != null && (ref.startsWith("ref: refs/") || ObjectId.isObjectId(ref));
    }
    
    /**
     * 判断该引用是否当前引用
     * 
     * @param git               仓库
     * @param ref               引用
     * @return                  =true表示该引用是当前引用
     * @throws IOException      异常
     */
    public static boolean isCurrentBranche(GitRefer refer, Ref ref) throws IOException
    {
        String name = ref.getUltimateTarget().getName();
        if (name.startsWith(P_REFS_HEADS_))
        {
            Ref head = refer.findRef(HEAD);
            while (head.isSymbolic())
            {
                head = head.getTarget();
                if (name.equals(head.getName()))
                    return true;
            }
        }
        
        return false;
    }
    
    /** 判断只有分枝的才写入 */
    public static boolean shouldAutoCreateLog(final String refName)
    {
        return refName.equals(HEAD) || refName.startsWith(P_REFS_HEADS_) || refName.startsWith(P_REFS_REMOTES_);
    }
    
    /**
     * 判断是否快捷方式引用
     * 
     * @param buf       字节数组
     * @param n         长度
     * @return
     */
    public static boolean isSymRef(String content)
    {
        return content.startsWith("ref: ");
    }
    
    /**
     * 判断列表中是否有引用名称的前缀
     * 
     * @param list      列表
     * @param prefix    前缀
     * @return          =true表示包含
     */
    public static final <E extends Ref> boolean isPrefix(List<E> list, String prefix)
    {
        for (Ref ref : list)
        {
            if (ref.getName().startsWith(prefix))
                return true;
        }
        
        return false;
    }
    
    /**
     * 检查仓库是否有提交，通过检查/objects或/objects/pack下时是否有文件
     * 
     * @param git    仓库
     * @return              =true表示有提交
     */
    public static boolean hasCommits(Git git)
    {
        if (git == null || !git.getMetaDir().exists())
            return false;
        
        return (new File(git.getMetaDir(), "objects").list().length > 2)
             || (new File(git.getMetaDir(), "objects/pack").list().length > 0);
    }
    
    /**
     * 判断是否是有效的引用名称
     * 1、不能包含在Git对象引用表达式中具有特殊含义的字符（~,@,^{,},:）。
     * 2、一些特殊字符也不允许，如（?,[,\,*,[）等
     * 
     * @param refName   引用名称
     * @return          =true表示有效
     */
    public static boolean isValidRefName(final String refName)
    {
        final int len = refName.length();
        if (len == 0)
            return false;
        
        if (refName.endsWith(_LOCK))
            return false;

        int components = 1;
        char p = '\0';
        for (int i = 0; i < len; i++)
        {
            final char c = refName.charAt(i);
            if (c <= ' ')
                return false;
            switch (c)
            {
            case '.':
                switch (p)
                {
                case '\0':
                case '/':
                case '.':
                    return false;
                }
                if (i == len - 1)
                    return false;
                break;
            case '/':
                if (i == 0 || i == len - 1)
                    return false;
                components++;
                break;
            case '{':
                if (p == '@')
                    return false;
                break;
            case '~':
            case '^':
            case ':':
            case '?':
            case '[':
            case '*':
            case '\\':
                return false;
            }
            p = c;
        }
        return components > 1;
    }
}
